/*
 * Copyright 2013 floreysoft GmbH (www.floreysoft.net)
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.floreysoft.gwt.drive.client.realtime;

import com.google.gwt.core.client.JsArray;

/**
 * 
 Class gapi.drive.realtime.CollaborativeList
 * 
 * A collaborative list. A list can contain other Realtime collaborative
 * objects, custom collaborative objects, JavaScript primitive values, or
 * JavaScript objects that can be serialized to JSON.
 * 
 * Changes to the list will automatically be synced with the server and other
 * collaborators. To listen for changes, add EventListeners for the following
 * event types:
 * 
 * gapi.drive.realtime.EventType.VALUES_ADDED
 * gapi.drive.realtime.EventType.VALUES_REMOVED
 * gapi.drive.realtime.EventType.VALUES_SET
 * 
 * This class should not be instantiated directly. To create a new list, use
 * gapi.drive.realtime.Model.prototype.createList().
 * 
 * @param <T>
 */
public final class CollaborativeList<T> extends CollaborativeObject {

	protected CollaborativeList() {
	}

	/**
	 * Removes all values from the list.
	 */
	public native void clear()/*-{
		this.clear();
	}-*/;

	/**
	 * Gets the value at the given index.
	 * 
	 * @param index
	 *            The index.
	 * @return The value at the given index.
	 */
	public native T get(int index) /*-{
		return this.get(index);
	}-*/;

	/**
	 * Adds an item to the end of the list.
	 * 
	 * @param value
	 *            The value to add.
	 * @return The new array length.
	 */
	public native int push(T value) /*-{
		return this.push(value) || 0;
	}-*/;

	/**
	 * Adds an array of values to the end of the list.
	 * 
	 * @param values
	 *            The values to add.
	 */
	@SuppressWarnings("rawtypes")
	public native void pushAll(JsArray values) /*-{
		this.pushAll(values);
	}-*/;

	/**
	 * Removes the item at the given index from the list.
	 * 
	 * @param index
	 *            The index of the item to remove.
	 */
	public native void remove(int index) /*-{
		this.remove(index);
	}-*/;

	/**
	 * Removes the items between startIndex (inclusive) and endIndex
	 * (exclusive).
	 * 
	 * @param startIndex
	 *            The start index of the range to remove (inclusive).
	 * @param endIndex
	 *            The end index of the range to remove (exclusive).
	 */
	public native void removeRange(int startIndex, int endIndex) /*-{
		this.remove(startIndex, endIndex);
	}-*/;

	/**
	 * Replaces items in the list with the given items, starting at the given
	 * index.
	 * 
	 * @param index
	 *            The index to set at.
	 * @param values
	 *            The values to insert.
	 */
	@SuppressWarnings("rawtypes")
	public native void replaceRange(int index, JsArray values) /*-{
		this.replaceRange(index, values);
	}-*/;

	/**
	 * Removes the first instance of the given value from the list.
	 * 
	 * @param index
	 *            The value to remove.
	 * @return Whether the item was removed.
	 */
	public native boolean removeValue(T index) /*-{
		return !!this.removeValue(index);
	}-*/;

	/**
	 * Returns the first index of the given value, or -1 if it cannot be found.
	 * 
	 * @param value
	 *            The value to find.
	 * @return The index of the given value, or -1 if it cannot be found.
	 */
	public native int indexOf(T value) /*-{
		return this.indexOf(value) || 0;
	}-*/;

	/**
	 * Returns the last index of the given value, or -1 if it cannot be found.
	 * 
	 * @param value
	 *            The value to find.
	 * @return The index of the given value, or -1 if it cannot be found.
	 */
	public native int lastIndexOf(T value) /*-{
		return this.lastIndexOf(value);
	}-*/;

	/**
	 * Creates an IndexReference at the given index. If canBeDeleted is true,
	 * then a delete over the index will delete the reference. Otherwise the
	 * reference will shift to the beginning of the deleted range.
	 * 
	 * @param index
	 *            The index of the reference.
	 * @param canBeDeleted
	 *            Whether this index is deleted when there is a delete of a
	 *            range covering this index.
	 * @return {@link IndexReference} The newly registered reference.
	 */
	public native IndexReference registerReference(int index, boolean canBeDeleted) /*-{
		return this.registerReference(index, canBeDeleted);
	}-*/;

	/**
	 * Inserts an item into the list at a given index.
	 * 
	 * @param index
	 *            The index to insert at.
	 * @param value
	 *            The value to add.
	 */
	public native void insert(int index, T value)/*-{
		this.insert(index, value);
	}-*/;

	/**
	 * Inserts a list of items into the list at a given index.
	 * 
	 * @param index
	 *            The index at which to insert.
	 * @param values
	 *            The values to insert.
	 */
	@SuppressWarnings("rawtypes")
	public native void insertAll(int index, JsArray values) /*-{
		this.insertAll(index, values);
	}-*/;

	/**
	 * Sets the item at the given index
	 * 
	 * @param index
	 *            The index to insert at.
	 * @param value
	 *            The value to set.
	 */
	public native void set(int index, T value) /*-{
		this.set(index, value);
	}-*/;

	/**
	 * @return The number of entries in the list. Assign to this field to reduce
	 *         the size of the list. Note that the length given must be < or
	 *         equal to the current size. The length of a list cannot be
	 *         extended in this way.
	 */
	public native int length() /*-{
		return this.length || 0;
	}-*/;

	/**
	 * Returns a copy of the contents of this collaborative list as a Javascript
	 * array. Changes to the returned object will not affect the original
	 * collaborative list.
	 * 
	 * @return A copy of the contents of this collaborative list.
	 */
	@SuppressWarnings("rawtypes")
	public native JsArray asArray() /*-{
		return this.asArray();
	}-*/;

}
